package com.factory.iamp.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.factory.iamp.dao.*;
import com.factory.iamp.pojo.*;
import com.factory.iamp.service.TableService;
import com.factory.iamp.utils.exception.APIException;
import com.factory.iamp.utils.helper.*;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

import static com.factory.iamp.utils.helper.CheckTypeCode.makeTypeCode;
import static com.factory.iamp.utils.helper.id2nameHelper.findObjectName;

@Service
@Transactional(rollbackFor = Throwable.class)
public class TableServiceImpl implements TableService {
    @Resource
    private TableMapper tableMapper;

    @Resource
    private TableContentMapper tableContentMapper;

    @Resource
    private UserMapper userMapper;

    @Resource
    private RoleMapper roleMapper;

    @Resource
    private TableTemplateHeaderMapper tableTemplateHeaderMapper;

    @Resource
    private TableTemplateBodyMapper tableTemplateBodyMapper;

    @Resource
    private TableTemplateTailMapper tableTemplateTailMapper;

    @Resource
    TemporaryTableMapper temporaryTableMapper;

    @Resource ArchiveDataLogMapper archiveDataLogMapper;

    private void recordId(Table table) {
        JSONObject data = JSONObject.parseObject(table.getHeader_value());
        String key;
        key = "orgNum";
        if(data.containsKey(key)) tableMapper.updateId(table.getTid(), "org_id", data.getString(key));
        key = "preNum";
        if(data.containsKey(key)) tableMapper.updateId(table.getTid(), "pre_cast_id", data.getString(key));
        key = "manuNum";
        if(data.containsKey(key)) tableMapper.updateId(table.getTid(), "sell_id", data.getString(key));
        key = "orderNum";
        if(data.containsKey(key)) tableMapper.updateId(table.getTid(), "order_id", data.getString(key));
        key = "projectName";
        if(data.containsKey(key)) tableMapper.updateId(table.getTid(), "name", data.getString(key));
    }

    private boolean NotValidValue(String index, String value) {
        JSONObject values = JSONObject.parseObject(value);
        if(values.containsKey("exportObj")) values = values.getJSONObject("exportObj");
        List<String> valuedIndex = new ArrayList<>(values.keySet());
        JSONArray jsonArray = JSONObject.parseArray(index);
        List<String> indexList = jsonArray.toJavaList(String.class);
        return !(indexList.containsAll(valuedIndex) && valuedIndex.containsAll(indexList));
    }

    private void checkDraft(Table result, int type, int lid) {
        if(result == null) throw new APIException(ResponseCode.DATABASE_FAILED, "草稿不存在");
        if(userMapper.findById(result.getHandler()) == null && type != 3)
            throw new APIException(ResponseCode.VALIDATE_FAILED, "检验员不存在");
        checkTemplate(result.getHeader_id(), result.getBody_list(), result.getTail_id(), lid);
        TableTemplateHeader tableTemplateHeader = tableTemplateHeaderMapper.findById(result.getHeader_id(), lid);
        if(NotValidValue(tableTemplateHeader.getFormat(), result.getHeader_value()))
            throw new APIException(ResponseCode.DATABASE_FAILED, "表头信息不完整");
        TableTemplateTail tableTemplateTail = tableTemplateTailMapper.findById(result.getTail_id(), lid);
        if(NotValidValue(tableTemplateTail.getFormat(), result.getTail_value()))
            throw new APIException(ResponseCode.DATABASE_FAILED, "表尾信息不完整");
    }

    private void checkTemplate(int header_id, List<Integer> body_list, int tail_id, int lid) {
        if(tableTemplateHeaderMapper.findById(header_id, lid) == null)
            throw new APIException(ResponseCode.VALIDATE_FAILED, "头模板不存在");
        List<Integer> checker = body_list.stream().distinct().collect(Collectors.toList());
        if(checker.size() < 1) throw new APIException(ResponseCode.VALIDATE_FAILED, "内容模板列表为空");
        if(tableTemplateBodyMapper.listCount(checker, lid) < checker.size())
            throw new APIException(ResponseCode.VALIDATE_FAILED, "含有不存在的内容模板id");
        if(tableTemplateTailMapper.findById(tail_id, lid) == null)
            throw new APIException(ResponseCode.VALIDATE_FAILED, "尾模板不存在");
    }

    private int makeUnfinishedContent(Table table) {
        if(table.getUnfinished_content() == -1) return -1;
        List<Integer> unfinishList = new ArrayList<>(table.getBody_list());
        int tid = table.getTid(), oid;
        for (int i: unfinishList) {
            oid = i;
            TableContent tableContent = tableContentMapper.findByTidOid(tid, oid);
            if(tableContent == null) return oid;
            if(tableContent.getScheck().equals("need")) return oid;
        }
        return -1;
    }

    private JSONArray makeCheckState(List<CheckLogQuery> logList) {
        JSONArray result = new JSONArray();
        JSONObject user = null;
        String last_uid = null;
        int total = 0;
        for(CheckLogQuery clq: logList) {
            if(last_uid == null || !last_uid.equals(clq.getUid())) {
                if(last_uid != null) {
                    user.put("total", total);
                    result.add(user);
                }
                total = 0;
                last_uid = clq.getUid();
                user = new JSONObject();
                for(int i = 1; i <= 12;i++) {
                    JSONObject tmp = new JSONObject();
                    for(int j = 1; j <= 3;j++) tmp.put(makeTypeCode(j).getName(), new ArrayList<String>());
                    user.put(findObjectName(i), tmp);
                }
                user.put("user", clq.getUsername());
            }
            total += 1;
            user.getObject(findObjectName(clq.getOid()), JSONObject.class)
                    .getObject(makeTypeCode(clq.getType()).getName(), List.class).add(clq.getName());
        }
        result.add(user);
        return result;
    }

    private boolean canDeleteTable(int tid, User user) {
        if(user.getRole() != roleMapper.findByName("系统管理员").getRid()) {
            Table target = tableMapper.findById(tid, user.getLine());
            if(target.getType() != 3) return false;
            return target.getCreator().equals(user.getUid()) && tableMapper.passToOtherCount(tid, user.getUid()) == 0;
        }
        return true;
    }

    private JSONObject unionJSON(JSONObject exportObj, JSONObject defaultValue, int num) {
        JSONObject result = new JSONObject();
        for(String key : exportObj.keySet()) result.put(key, exportObj.get(key));
        for(String key : defaultValue.keySet()) result.put(key, defaultValue.get(key));
        result.put("num", num);
        return JSONObject.parseObject(result.toJSONString());
    }

    @Override
    public int Count(int lid) {
        return tableMapper.Count(lid);
    }

    @Override
    public int findUnfinishedProblemTableCount() {
        return tableMapper.findUnfinishedProblemTableCount();
    }

    @Override
    public int QueryCount(String QueryStr, int lid) {
        return tableMapper.QueryCount(QueryStr, lid);
    }

    @Override
    public int CountByProblem(int pid, String QueryStr, String order, int filter) {
        String O;
        if(order.equals("2")) O = "desc";
        else O = "asc";
        if(filter == -1) return tableMapper.CountByProblem(pid, QueryStr, O);
        else return tableMapper.CountMainByProblem(pid, QueryStr, O);
    }

    @Override
    public int StoreCount(String QueryStr, int lid, int filter) {
        if(filter == -1) return tableMapper.StoreCount(QueryStr, lid);
        else return tableMapper.StoreMainCount(QueryStr, lid);
    }

    @Override
    public int findAssemblyCount(String QueryStr, int lid) {
        return tableMapper.findAssemblyCount(QueryStr, lid);
    }

    @Override
    public int findBySellidCount(List<Integer> sid, int lid) {
        StringBuilder sids = new StringBuilder("(-1");
        for(int id: sid) sids.append(", ").append(id);
        sids.append(")");
        return tableMapper.findBySellidCount(sids.toString(), lid);
    }

    @Override
    public int PublishCount(int lid) {
        return tableMapper.PublishCount(lid);
    }

    @Override
    public int findByNameCount(String name, int lid) {
        return tableMapper.findByNameCount(name, lid);
    }

    @Override
    public int findMyCount(String uid, String QueryStr, int lid, int filter) {
        if(filter == -1) return tableMapper.findMyCount(uid, QueryStr, lid);
        else return tableMapper.findMyCountMain(uid, QueryStr, lid);
    }

    @Override
    public int findByCreatorCount(String uid, String QueryStr, int lid, int filter) {
        if(filter == -1) return tableMapper.findByCreatorCount(uid, QueryStr, lid);
        else return tableMapper.findMainByCreatorCount(uid, QueryStr, lid);
    }

    @Override
    public int findByHandlerCount(String uid, String QueryStr, int lid, int filter) {
        if(filter == -1) return tableMapper.findByHandlerCount(uid, QueryStr, lid);
        else return tableMapper.findByHandlerMainCount(uid, QueryStr, lid);
    }

    @Override
    public int findMyPassedTableCount(
            String uid, String name, List<Integer> typeList, String begin, String end, int lid, int filter
    ) {
        if(filter == -1) return tableMapper.findMyPassedTableCount(uid, name, typeList, begin, end, lid);
        else return tableMapper.findMainMyPassedTableCount(uid, name, typeList, begin, end, lid);
    }

    @Override
    public int SubTableCount(int tid, int lid) {
        return tableMapper.SubTableCount(tid, lid);
    }

    @Override
    public int DraftCount(String uid, String QueryStr, int lid) {
        return tableMapper.DraftCount(uid, QueryStr, lid);
    }

    private List<JSONObject> getDIDData(
            List<ArchiveDataLog> adLogList, int range, LocalDate date, DateTimeFormatter formatter, int line
    ) {
        List<JSONObject> result = new ArrayList<>();
        for(int i = 0;i < range;i++) {
            JSONObject obj = new JSONObject();
            obj.put("count", 0);
            obj.put("problem", 0);
            obj.put("result", 0);
            obj.put("target", 0.3);
            obj.put("time", date.minusDays(range - 1 - i).format(formatter));
            result.add(obj);
        }
        int tmp = 0;
        for(ArchiveDataLog adLog: adLogList) {
            while(!result.get(tmp).getString("time").equals(adLog.getCreated_at())) tmp += 1;
            result.get(tmp).put("count", adLog.getTable_count(line));
            result.get(tmp).put("problem", adLog.getProblem_count(line));
            if(adLog.getTable_count(line) == 0) result.get(tmp).put("result", 0.0);
            else result.get(tmp).put("result", 1.0 * adLog.getProblem_count(line) / adLog.getTable_count(line));
        }
        return result;
    }

    @Override
    public List<JSONObject> getDeliveryInspectionData(int range, int line) {
        LocalDate date = LocalDate.now();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        return getDIDData(archiveDataLogMapper.findBetweenDate(
                date.minusDays(range - 1).format(formatter), date.format(formatter)
        ), range, date, formatter, line);
    }

    @Override
    public Object getProblemRecordData(int lid) {
        Map<String, Map<String, Integer>> result = new HashMap<>();
        LocalDate date = LocalDate.now();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        List<Table> tableList = tableMapper.getArchiveDataByDay(
                date.minusDays(7).format(formatter), date.format(formatter), lid
        );
        for(Table t: tableList) {
            JSONArray header = JSONArray.parseArray(t.getHeader_value());
            String project_name = "";
            for(Object h_content: header) {
                if(((JSONObject)h_content).getObject("name", String.class).equals("project_name")) {
                    project_name = ((JSONObject)h_content).getObject("value", String.class);
                    break;
                }
            }
            if(project_name.length() < 1) throw new APIException(ResponseCode.VALIDATE_FAILED, "表单不存在工程名称项");
            if(!result.containsKey(project_name)) result.put(project_name, TableProblemHelper.ProblemMap());
            Map<String, Integer> tmp = result.get(project_name);
            JSONArray problems = JSONArray.parseArray(t.getProblem());
            String problem_name;
            for(Object p: problems) {
                if(!((JSONObject)p).containsKey("list"))
                    throw new APIException(ResponseCode.DATABASE_FAILED, "不存在问题列表项");
                JSONArray problemList = ((JSONObject)p).getJSONArray("list");
                for(Object pid: problemList) {
                    problem_name = TableProblemHelper.findProblemName((int)pid);
                    if(!tmp.containsKey(problem_name)) tmp.put(problem_name, 0);
                    tmp.put(problem_name, tmp.get(problem_name) + 1);
                }
            }
            result.put(project_name, tmp);
        }
        return result;
    }

    @Override
    public JSONArray getCheckStateByName(String QueryStr, String name, int lid) {
        List<CheckLogQuery> logList = tableMapper.checkLogQuery(name, QueryStr, lid);
        return makeCheckState(logList);
    }

    @Override
    public List<CheckLog> getTableCheckTime(int tid) {
        return tableMapper.getTableCheckTime(tid);
    }

    @Override
    public List<QuestionLog> getTableProblemSign(int tid) {
        return tableMapper.getTableProblemAll(tid);
    }

    @Override
    public List<Table> findUnfinishedProblemTableListPaged(PageHelper data, int lid) {
        return tableMapper.findUnfinishedProblemTableListPaged(data.calOffset(), data.getLimit(), lid);
    }

    @Override
    public JSONArray getCheckStateByTableList(String QueryStr, int lid) {
        List<CheckLogQuery> logList = tableMapper.checkLogQuery("%%", QueryStr, lid);
        return makeCheckState(logList);
    }

    @Override
    public JSONObject addAssemblyTable(JSONObject data, int lid) {
        TableAssembly tableAssembly = new TableAssembly(data);
        if(tableAssembly.insertCheck()) throw new APIException(ResponseCode.VALIDATE_FAILED, "模板名称不存在");
        if(tableMapper.findAssemblyByName(tableAssembly.getName(), lid) != null)
            throw new APIException(ResponseCode.VALIDATE_FAILED, "模板名称重复");
        checkTemplate(tableAssembly.getHeader_id(), tableAssembly.getBody_list(), tableAssembly.getTail_id(), lid);
        tableMapper.addAssemblyTable(tableAssembly);
        return data;
    }

    @Override
    public TableAssembly alterAssemblyTable(int aid, JSONObject data, int lid) {
        TableAssembly tableAssembly = tableMapper.findAssemblyById(aid, lid);
        if(tableAssembly == null) throw new APIException(ResponseCode.VALIDATE_FAILED, "模板不存在");
        tableAssembly.SetAll(data);
        tableMapper.alterAssemblyTable(tableAssembly);
        return tableAssembly;
    }

    @Override
    public TableAssembly copyAssemblyTable(String name, int aid, int lid) {
        if(tableMapper.findAssemblyByName(name, lid) != null)
            throw new APIException(ResponseCode.VALIDATE_FAILED, "模板名称重复");
        TableAssembly tableAssembly = tableMapper.findAssemblyById(aid, lid);
        tableAssembly.setName(name);
        tableMapper.addAssemblyTable(tableAssembly);
        return tableMapper.findAssemblyByName(name, lid);
    }

    @Override
    public TableDetail getTableById(int tid, int lid) {
        TableDetail result = tableMapper.findPublishByIdDetail(tid, lid);
        result.setBody_data(tableContentMapper.findByIdList(result.getBody_list(), result.getTid()));
        result.renewBodyData();
        return result;
    }

    @Override
    public Table passTableToUid(int tid, String uid, String user, int lid) {
        if(userMapper.findById(uid) == null) throw new APIException(ResponseCode.DATABASE_FAILED, "不存在该用户");
        Table result = tableMapper.findPublishById(tid, lid);
        if(result == null) throw new APIException(ResponseCode.DATABASE_FAILED, "不存在该表单");
        if(!result.getHandler().equals(user)) throw new APIException(ResponseCode.VALIDATE_FAILED, "该表单未流转到您");
        if(result.getFtid() != -1) throw new APIException(ResponseCode.VALIDATE_FAILED, "该表单并非主工单，请对主工单进行流转操作");
        for (int subtid: result.getSubTable()) {
            tableMapper.passTableToUid(subtid, uid);
            tableMapper.addPassLog(subtid, user, uid);
        }
        tableMapper.passTableToUid(tid, uid);
        tableMapper.addPassLog(tid, user, uid);
        result.setHandler(uid);
        return result;
    }

    @Override
    public Table updatePrecastId(int tid, String precastid, String user, int lid) {
        tableMapper.updateId(tid, "pre_cast_id", precastid);
        Table result = tableMapper.findByIdCreator(tid, user, lid);
        if(result == null) throw new APIException(ResponseCode.DATABASE_FAILED, "不存在该表单");
        return result;
    }

    @Override
    public Table updateSellId(int tid, String sellid, String user, int lid) {
        tableMapper.updateId(tid, "sell_id", sellid);
        Table result = tableMapper.findByIdCreator(tid, user, lid);
        if(result == null) throw new APIException(ResponseCode.DATABASE_FAILED, "不存在该表单");
        return result;
    }

    @Override
    public List<Table> ListPaged(PageHelper data, int lid) {
        return tableMapper.ListPaged(data.calOffset(), data.getLimit(), lid);
    }

    @Override
    public List<Table> QueryListPaged(PageHelper data, String QueryStr, int lid) {
        return tableMapper.QueryListPaged(data.calOffset(), data.getLimit(), QueryStr, lid);
    }

    @Override
    public List<Table> ListByProblemPaged(PageHelper data, int pid, String QueryStr, String order, int lid, int filter) {
        String O;
        if(order.equals("2")) O = "desc";
        else O = "asc";
        if(filter == -1) return tableMapper.ListByProblemPaged(data.calOffset(), data.getLimit(), pid, QueryStr, O, lid);
        else return tableMapper.ListMainByProblemPaged(data.calOffset(), data.getLimit(), pid, QueryStr, O, lid);
    }

    @Override
    public List<TableForStoreList> StoreListPaged(PageHelper data, String QueryStr, String Order, User user, int filter) {
        String O = "unfinished_content";
        if(Order.equals("2")) O = "tid desc, " + O;
        if(Order.equals("1")) O = "tid asc, " + O;
        List<Table> query_result;
        if(filter == -1) query_result = tableMapper.StoreListPaged(
                data.calOffset(), data.getLimit(), QueryStr, O, user.getLine()
        );
        else query_result = tableMapper.StoreMainListPaged(
                data.calOffset(), data.getLimit(), QueryStr, O, user.getLine()
        );
        List<TableForStoreList> result = new ArrayList<>();
        for(Table x: query_result) result.add(new TableForStoreList(x));
        for(TableForStoreList x: result) x.setCan_delete(canDeleteTable(x.getTid(), user)? 1: 0);
        return result;
    }

    @Override
    public List<TableAssembly> findAssemblyListPaged(PageHelper data, String QueryStr, int lid) {
        return tableMapper.findAssemblyListPaged(data.calOffset(), data.getLimit(), QueryStr, lid);
    }

    @Override
    public List<Table> findByNameListPaged(PageHelper data, String name, int lid) {
        return tableMapper.findByNameListPaged(data.calOffset(), data.getLimit(), name, lid);
    }

    @Override
    public List<Table> findBySellidListPaged(PageHelper data, List<Integer> sid, int lid) {
        StringBuilder sids = new StringBuilder("(-1");
        for(int id: sid) sids.append(", ").append(id);
        sids.append(")");
        return tableMapper.findBySellidListPaged(data.calOffset(), data.getLimit(), sids.toString(), lid);
    }

    @Override
    public List<Table> findMyListPaged(PageHelper data, String uid, String QueryStr, int lid, int filter) {
        if(filter == -1) return tableMapper.findMyListPaged(data.calOffset(), data.getLimit(), uid, QueryStr, lid);
        else return tableMapper.findMyMainListPaged(data.calOffset(), data.getLimit(), uid, QueryStr, lid);
    }

    @Override
    public List<Table> findByCreatorListPaged(PageHelper data, String uid, String QueryStr, int lid, int filter) {
        if(filter == -1) return tableMapper.findByCreatorListPaged(data.calOffset(), data.getLimit(), uid, QueryStr, lid);
        else return tableMapper.findMainByCreatorListPaged(data.calOffset(), data.getLimit(), uid, QueryStr, lid);
    }

    @Override
    public List<Table> findByHandlerListPaged(PageHelper data, String uid, String QueryStr, int lid, int filter) {
        if(filter == -1) return tableMapper.findByHandlerListPaged(data.calOffset(), data.getLimit(), uid, QueryStr, lid);
        else return tableMapper.findByHandlerMainListPaged(data.calOffset(), data.getLimit(), uid, QueryStr, lid);
    }

    @Override
    public List<Table> findMyPassedTableListPaged(
            PageHelper data, String uid, String name, List<Integer> typeList, String begin, String end, int lid, int filter
    ) {
        if(filter == -1) return tableMapper.findMyPassedTableListPaged(
                data.calOffset(), data.getLimit(), uid, name, typeList, begin, end, lid
        );
        else return tableMapper.findMainMyPassedTableListPaged(
                data.calOffset(), data.getLimit(), uid, name, typeList, begin, end, lid
        );
    }

    @Override
    public List<Table> SubTableListPaged(PageHelper data, int tid, int lid) {
        return tableMapper.SubTableListPaged(data.calOffset(), data.getLimit(), tid, lid);
    }

    @Override
    public List<Table> DraftListPaged(PageHelper data, String uid, String QueryStr, int lid) {
        return tableMapper.DraftListPaged(data.calOffset(), data.getLimit(), uid, QueryStr, lid);
    }

    @Override
    public Table addDraftTable(Table table, int lid) {
        Table databaseTable = tableMapper.findSelfDraftByName(table.getName(), table.getCreator(), lid);
        if(databaseTable != null) throw new APIException(ResponseCode.DATABASE_FAILED, "已存在同名草稿");
        table.insertCheck();
        tableMapper.addDraftTable(table);
        recordId(table);
        tableMapper.setUnfinishedContent(table.getTid(), makeUnfinishedContent(table));
        return table;
    }

    @Override
    public Table alterDraftTable(int tid, String uid, JSONObject data, int lid) {
        Table table = tableMapper.findSelfDraftById(tid, uid, lid);
        if(table == null) throw new APIException(ResponseCode.DATABASE_FAILED, "不存在草稿");
        table.SetAll(data);
        table.insertCheck();
        tableMapper.alterDraftTable(table);
        recordId(table);
        tableMapper.setUnfinishedContent(table.getTid(), makeUnfinishedContent(table));
        return table;
    }

    @Override
    public Table alterTable(int tid, String uid, JSONObject data, int lid) {
        Table table = tableMapper.findById(tid, lid);
        if(table == null || !table.getCreator().equals(uid)) throw new APIException(ResponseCode.DATABASE_FAILED, "不存在表单");
        table.SetAll(data);
        table.insertCheck();
        tableMapper.alterDraftTable(table);
        recordId(table);
        tableMapper.setUnfinishedContent(table.getTid(), makeUnfinishedContent(table));
        return table;
    }

    @Override
    public Table publishDraftTable(int tid, String uid, int lid) {
        Table result = tableMapper.findSelfDraftById(tid, uid, lid);
        checkDraft(result, 1, lid);
        tableMapper.publishDraftTable(tid, uid);
        JSONObject Body_Content = JSONObject.parseObject(result.getBody_value());
        for(String k: Body_Content.keySet()) {
            TableContent tableContent = new TableContent();
            tableContent.setContent(Body_Content.getJSONObject(k));
            fillTableContent(tid, Integer.parseInt(k), uid, tableContent, lid);
        }
        result.setType(1);
        tableMapper.addPassLog(tid, uid, result.getHandler());
        return result;
    }

    @Override
    public Table storeDraftTable(int tid, String uid, int lid) {
        Table result = tableMapper.findSelfDraftById(tid, uid, lid);
        checkDraft(result, 3, lid);
        tableMapper.storeDraftTable(tid, uid);
        JSONObject Body_Content = JSONObject.parseObject(result.getBody_value());
        for(String k: Body_Content.keySet()) {
            TableContent tableContent = new TableContent();
            tableContent.setContent(Body_Content.getJSONObject(k));
            fillTableContent(tid, Integer.parseInt(k), uid, tableContent, lid);
        }
        result.setType(3);
        return result;
    }

    @Override
    public void setFatherTable(int tid, int ftid) {
        tableMapper.setFatherTable(tid, ftid);
    }

    @Override
    public Table returnFactory(int tid, String reason, String process, int lid) {
        Table result = tableMapper.findArchivedById(tid, lid);
        if(result == null) throw new APIException(ResponseCode.VALIDATE_FAILED, "不存在该表单");
        tableMapper.returnFactory(tid, reason, process);
        result.setReturn_reason(reason);
        result.setReturn_process(process);
        return result;
    }

    @Override
    public void deleteDraftTable(int tid, String uid, int lid) {
        if(tableMapper.findSelfDraftById(tid, uid, lid) == null)
            throw new APIException(ResponseCode.DATABASE_FAILED, "草稿不存在");
        tableMapper.deleteDraftTable(tid, uid);
    }

    @Override
    public void deleteAssemblyTable(int aid, User user) {
        String QueryStr = "aid = " + aid;
        if(!roleMapper.findById(user.getRole()).getDeleteAssemblyTable()) QueryStr += " and creator = " + user.getUid();
        tableMapper.deleteAssemblyTable(QueryStr);
    }

    @Override
    public void deleteTableContentSign(int tid, int oid, User user, int type) {
        if(tableMapper.QueryCount("type != 2 and tid = \"" + tid + "\"", user.getLine()) < 1)
            throw new APIException(ResponseCode.VALIDATE_FAILED, "该表单不存在");
        String QueryStr = "tid = " + tid + " and oid = " + oid;
        if(!roleMapper.findById(user.getRole()).getDeleteTableContentSign()) QueryStr += " and uid = " + user.getUid();
        if(tableMapper.findCheckLog(type + 1, QueryStr) != null)
            throw new APIException(ResponseCode.VALIDATE_FAILED, "不满足条件，无法撤销签名");
        tableMapper.deleteCheckLog(type, QueryStr);
        tableMapper.deleteCheckFile(tid, oid, CheckTypeCode.makeTypeCode(type).getBase());
    }

    @Override
    public void deleteTableQuestion(int tid, int oid, String uid, int lid) {
        if(tableMapper.QueryCount("type != 2 and tid = \"" + tid + "\"", lid) < 1)
            throw new APIException(ResponseCode.VALIDATE_FAILED, "不存在该表单");
        if(tableContentMapper.findQuestionLog(tid, oid, uid) == null)
            throw new APIException(ResponseCode.VALIDATE_FAILED, "不存在该问题");
        tableContentMapper.removeTableQuestion(tid, oid);
        tableContentMapper.deleteQuestionLog(tid, oid, uid);
    }

    @Override
    public void deleteTableQuestionSign(int tid, int oid, String uid, int lid) {
        if(tableMapper.QueryCount("type != 2 and tid = \"" + tid + "\"", lid) < 1)
            throw new APIException(ResponseCode.VALIDATE_FAILED, "不存在该表单");
        tableContentMapper.removeTableQuestionSign(tid, oid, uid);
    }

    @Override
    public void deleteTableProblemSign(int tid, int oid, String uid, int lid) {
        if(tableMapper.QueryCount("type != 2 and tid = \"" + tid + "\"", lid) < 1)
            throw new APIException(ResponseCode.VALIDATE_FAILED, "不存在该表单");
        TableContent content = tableContentMapper.findByTidOid(tid, oid);
        JSONObject problem = JSONObject.parseObject(content.getProblem());
        problem.put("sign", "");
        tableContentMapper.updateTableQuestion(tid, oid, problem.toString());
    }

    @Override
    public void deleteTable(int tid, User user){
        if(canDeleteTable(tid, user)) tableMapper.deleteTable(tid);
    }

    @Override
    public TableContent fillTableContent(int tid, int oid, String uid, TableContent tableContent, int lid) {
        Table table = tableMapper.findSelfPublishById(tid, uid, lid);
        if(table == null) throw new APIException(ResponseCode.DATABASE_FAILED, "表不存在");
        if(!table.getBody_list().contains(oid))
            throw new APIException(ResponseCode.VALIDATE_FAILED, "填写的内容模板不存在");
        TableContent checker = tableContentMapper.findByTidOid(tid, oid);
        if(checker == null) {
            tableContent.setTid(tid);
            tableContent.setOid(oid);
            TableTemplateBody tableTemplateBody = tableTemplateBodyMapper.findById(oid, lid);
            if(tableTemplateBody.getFormat().contains("Scheck")) tableContent.setScheck("need");
            else tableContent.setScheck("");
            if(tableTemplateBody.getFormat().contains("Ocheck")) tableContent.setOcheck("need");
            else tableContent.setOcheck("");
            if(tableTemplateBody.getFormat().contains("Zcheck")) tableContent.setZcheck("need");
            else tableContent.setZcheck("");
            tableContentMapper.addTableContent(tableContent);
        } else tableContentMapper.alterTableContent(checker.getCid(), tableContent.getContent());
       return tableContentMapper.findByTidOid(tid, oid);
    }

    @Override
    public Table fillTableHead(int tid, String uid, String content, int lid) {
        Table table = tableMapper.findSelfPublishById(tid, uid, lid);
        if(table == null) throw new APIException(ResponseCode.DATABASE_FAILED, "表不存在");
        tableContentMapper.alterTableHead(tid, content);
        table = tableMapper.findSelfPublishById(tid, uid, lid);
        recordId(table);
        return table;
    }

    @Override
    public TableContent checkTableContent(
            int tid, int oid, int type, String uid, String img_path, int lid
    ) throws Throwable {
        if(img_path == null || img_path.length() < 1)
            throw new APIException(ResponseCode.VALIDATE_FAILED, "用户尚未上传签名图片");
        CheckTypeCode typeCode = makeTypeCode(type);
        Table table;
        if(type == CheckTypeCode.ZCheck.getCode()) table = tableMapper.findPublishById(tid, lid);
        else table = tableMapper.findHandlePublishById(tid, uid, lid);
        if(table == null) throw new APIException(ResponseCode.VALIDATE_FAILED, "不存在该表单");
        TableContent tableContent = tableContentMapper.findByTidOid(tid, oid);
        if(tableContent == null) throw new APIException(ResponseCode.VALIDATE_FAILED, "该表单项未填写");
        if(!tableContent.ReflectGet(typeCode.getBase()).equals("need"))
            throw new APIException(ResponseCode.VALIDATE_FAILED, "该表单项不需要或已进行" + typeCode.getName());
        TableTemplateBody tableTemplateBody = tableTemplateBodyMapper.findById(oid, lid);
        JSONObject bodyValue = JSONObject.parseObject(table.getBody_value());
        JSONObject contentValue = bodyValue.getObject(String.valueOf(oid), JSONObject.class);
        if(!contentValue.containsKey("exportObj"))
            CheckTableHelper.ValidCheck(typeCode, contentValue, tableContent, tableTemplateBody);
        tableContentMapper.addTableContentCheck(tableContent.getCid(), typeCode.getBase(), img_path);
        tableMapper.setUnfinishedContent(table.getTid(), makeUnfinishedContent(table));
        tableMapper.addCheckLog(uid, tid, oid, type);
        return tableContentMapper.findById(tableContent.getCid());
    }

    @Override
    public TableContent addTableContentProblem(
            int tid, int oid, String uid, JSONObject problem, String img_path
    ) throws Throwable {
        problem.put("sign", img_path);
        String old_data = tableContentMapper.getDumpQuestionLog(tid, oid);
        tableContentMapper.deleteDumpQuestionLog(tid, oid);
        tableContentMapper.addTableContentProblem(tid, oid, problem.toString());
        TableContent result = tableContentMapper.findByTidOid(tid, oid);
        if(result == null) throw new APIException(ResponseCode.DATABASE_FAILED, "不存在该表单项");
        tableContentMapper.addProblemLog(tid, oid, uid, problem.getString("list"), old_data);
        return result;
    }

    @Override
    public void processTableContentProblem(int tid, int oid, String uid, String record, String img_path) {
        tableContentMapper.processProblemLog(tid, oid, uid, record, img_path);
    }

    @Override
    public Table claimTable(int tid, String uid, int lid) {
        Table result = tableMapper.findStoreById(tid, lid);
        if(result == null) throw new APIException(ResponseCode.VALIDATE_FAILED, "该表单不存在");
        tableMapper.addPassLog(tid, result.getHandler(), uid);
        tableMapper.claimTable(tid, uid);
        return tableMapper.findPublishById(tid, lid);
    }

    @Override
    public Table storeTable(int tid, int lid) {
        Table result = tableMapper.findPublishById(tid, lid);
        if(result == null) throw new APIException(ResponseCode.VALIDATE_FAILED, "该表单不存在");
        tableMapper.storeTable(tid);
        return tableMapper.findStoreById(tid, lid);
    }


    private Table archiveSingleTable(int tid, int lid) {
        Table result = tableMapper.findPublishById(tid, lid);
        if(result == null) throw new APIException(ResponseCode.VALIDATE_FAILED, "id为 " + tid + " 的表单不存在");
        if(result.getUnfinished_question() > 0)
            throw new APIException(ResponseCode.VALIDATE_FAILED, "id为 " + tid + " 的表单存在未完成问题");
        List<TableContent> contentList = tableContentMapper.findByIdList(result.getBody_list(), tid);
        if(contentList.size() != result.getBody_list().size())
            throw new APIException(ResponseCode.DATABASE_FAILED, "id为 " + tid + " 的表单尚未填写完毕");
        JSONArray problems = new JSONArray();
        JSONObject test;
        for(TableContent content: contentList) {
            if(
                    content.getScheck().equals("need") || content.getOcheck().equals("need") ||
                            content.getZcheck().equals("need")
            ) throw new APIException(ResponseCode.DATABASE_FAILED, "id为 " + tid + " 的表单尚未质检完毕");
            test = JSONObject.parseObject(content.getProblem());
            if(test != null) problems.add(test);
        }
        tableMapper.archiveTable(tid, problems.toString());
        tableMapper.addArchiveLog(tid);
        result = tableMapper.findArchivedById(tid, lid);
        LocalDate date = LocalDate.now();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        String created_at = date.format(formatter);
        ArchiveDataLog adLog = archiveDataLogMapper.findByDate(created_at);
        if(adLog == null) {
            archiveDataLogMapper.addLog(created_at);
            adLog = archiveDataLogMapper.findByDate(created_at);
        }
        adLog.addTable(result);
        archiveDataLogMapper.updateLog(adLog);
        return result;
    }

    @Override
    public Table archiveTable(int tid, int lid) {
        Table result = tableMapper.findPublishById(tid, lid);
        if(result == null) throw new APIException(ResponseCode.VALIDATE_FAILED, "该表单不存在");
        if(result.getFtid() != -1) throw new APIException(ResponseCode.VALIDATE_FAILED, "该表单并非主工单，请对主工单进行归档操作");
        for(int subtid: result.getSubTable()) archiveSingleTable(subtid, lid);
        return archiveSingleTable(tid, lid);
    }

    @Override
    public String makeTableFile(int tid, int lid) {
        Table data = tableMapper.findArchivedById(tid, lid);
        if(data == null) throw new APIException(ResponseCode.DATABASE_FAILED, "不存在该表单");
        if(data.getFile_path() != null && data.getFile_path().length() > 0) return data.getFile_path();
        List<String> fileList = new ArrayList<>();
        TableTemplateHeader header = tableTemplateHeaderMapper.findById(data.getHeader_id(), lid);
        if(header == null) throw new APIException(ResponseCode.DATABASE_FAILED, "不存在该表单头模板");
        fileList.add(FileUploadHelper.getBasePath() + header.getFile_path());
        temporaryTableMapper.dropIdListForQuery();
        temporaryTableMapper.idListForQuery();
        temporaryTableMapper.addIdList(data.getBody_list());
        List<TableTemplateBody> bodies = tableTemplateBodyMapper.findAllById(lid);
        List<JSONObject> content_value = tableContentMapper.findValueByIdList(tid);
        for(int i = 0;i < bodies.size();i++) {
            if(bodies.get(i) == null) throw new APIException(ResponseCode.DATABASE_FAILED, "不存在该表单项模板");
            fileList.add(FileUploadHelper.getBasePath() + bodies.get(i).getFile_path());
            if(content_value.get(i).getJSONObject("content").containsKey("exportObj")) {
                content_value.get(i).put("content", unionJSON(
                        content_value.get(i).getJSONObject("content").getJSONObject("exportObj"),
                        JSONObject.parseObject(bodies.get(i).getDefaultValue()),
                        content_value.get(i).getJSONObject("content").getInteger("num")
                ));
            }
        }
        TableTemplateTail tail = tableTemplateTailMapper.findById(data.getTail_id(), lid);
        if(tail == null) throw new APIException(ResponseCode.DATABASE_FAILED, "不存在该表单尾模板");
        fileList.add(FileUploadHelper.getBasePath() + tail.getFile_path());
        String result = ExcelHelper.makeTableFile(data, content_value, fileList, "/data/table/" + tid + "/");
        tableMapper.addFilePath(tid, result);
        return result;
    }

    private JSONObject transSevenDayData(
            int range, List<ArchiveDataLog> adLogList, LocalDate date, DateTimeFormatter formatter, int line
    ) {
        JSONObject result = new JSONObject();
        int[] SevenDaySub = new int[range];
        int[] SevenDayFault = new int[range];
        Map<String, Integer> faultMap = TableProblemHelper.ProblemMap();
        int tmp = 0;
        String[] DateList = new String[range];
        for(int i = 0;i < range;i++) DateList[i] = date.minusDays(range - 1 - i).format(formatter);
        for(ArchiveDataLog adLog: adLogList) {
            while(!DateList[tmp].equals(adLog.getCreated_at())) tmp += 1;
            SevenDaySub[tmp] = adLog.getTable_count(line);
            SevenDayFault[tmp] = adLog.getProblem_count(line);
            JSONObject pcc = JSONObject.parseObject(adLog.getProblem_class_count(line));
            for(String pids: pcc.keySet()) {
                int pid = Integer.parseInt(pids);
                String pname = TableProblemHelper.findProblemName(pid);
                faultMap.put(pname, faultMap.get(pname) + pcc.getInteger(pids));
            }
        }
        result.put("SevenDaySub", SevenDaySub);
        result.put("SevenDayFault", SevenDayFault);
        result.put("SevenDayFaultClass", faultMap);
        return result;
    }

    @Override
    public JSONObject makeSevenDayData(int range) {
        LocalDate date = LocalDate.now();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        return transSevenDayData(range, archiveDataLogMapper.findBetweenDate(
                date.minusDays(range - 1).format(formatter), date.format(formatter)
        ), date, formatter, -1);
    }

    @Override
    public JSONObject makeSevenDayDataLine(int range, int line) {
        LocalDate date = LocalDate.now();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        return transSevenDayData(range, archiveDataLogMapper.findBetweenDate(
                date.minusDays(range - 1).format(formatter), date.format(formatter)
        ), date, formatter, line);
    }
}
